package com.cheng.im.service.user.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheng.im.common.constants.RedisConstants;
import com.cheng.im.common.constants.SeqConstants;
import com.cheng.im.common.entity.ImNode;
import com.cheng.im.service.balance.ImLoadBalance;
import com.cheng.im.service.common.eunms.DelFlagEnum;
import com.cheng.im.service.common.eunms.UserErrorCode;
import com.cheng.im.service.common.exception.ApplicationException;
import com.cheng.im.service.common.resp.CommonResult;
import com.cheng.im.service.group.service.ImGroupService;
import com.cheng.im.service.user.domain.ImUserData;
import com.cheng.im.service.user.model.req.*;
import com.cheng.im.service.user.model.resp.GetUserInfoResp;
import com.cheng.im.service.user.model.resp.ImportUserResp;
import com.cheng.im.service.user.model.resp.UserLoginResp;
import com.cheng.im.service.user.service.ImUserDataService;
import com.cheng.im.service.user.mapper.ImUserDataMapper;
import com.cheng.im.service.util.JwtUtil;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* @author Cheng
* @description 针对表【im_user_data(im模块的im用户表)】的数据库操作Service实现
* @createDate 2024-12-17 08:59:23
*/
@DubboService
public class ImUserDataServiceImpl extends ServiceImpl<ImUserDataMapper, ImUserData>
    implements ImUserDataService {

    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    ImLoadBalance imLoadBalance;
    @Resource
    ImGroupService imGroupService;

    @Override
    public CommonResult<ImportUserResp> importUser(ImportUserReq req) {

        if(req.getUserData().size() > 100){
            return CommonResult.failed(UserErrorCode.IMPORT_SIZE_BEYOND);
        }

        ImportUserResp resp = new ImportUserResp();
        List<String> successId = new ArrayList<>();
        List<String> errorId = new ArrayList<>();

        for (ImUserData data : req.getUserData()) {
            try {
                data.setDelFlag(DelFlagEnum.NORMAL.getCode());
                data.setAppId(req.getAppId());
                int insert = baseMapper.insert(data);
                if(insert == 1){
                    successId.add(data.getUserId());
                }
            }catch (Exception e){
                e.printStackTrace();
                errorId.add(data.getUserId());
            }
        }

        resp.setErrorId(errorId);
        resp.setSuccessId(successId);
        return CommonResult.success(resp);
    }

    @Override
    public CommonResult<GetUserInfoResp> getUserInfo(GetUserInfoReq req) {

        LambdaQueryWrapper<ImUserData> imUserDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
        imUserDataLambdaQueryWrapper.eq(ImUserData::getAppId, req.getAppId());
        imUserDataLambdaQueryWrapper.in(ImUserData::getUserId, req.getUserIds());

        imUserDataLambdaQueryWrapper.eq(ImUserData::getDelFlag, DelFlagEnum.NORMAL.getCode());

        List<ImUserData> userDataEntities = baseMapper.selectList(imUserDataLambdaQueryWrapper);
        HashMap<String, ImUserData> map = new HashMap<>();

        for (ImUserData data : userDataEntities) {
            map.put(data.getUserId(),data);
        }

        List<String> failUser = new ArrayList<>();
        for (String uid : req.getUserIds()) {
            if(!map.containsKey(uid)){
                failUser.add(uid);
            }
        }

        GetUserInfoResp resp = new GetUserInfoResp();
        resp.setUserDataItem(userDataEntities);
        resp.setFailUser(failUser);
        return CommonResult.success(resp);
    }

    @Override
    @Transactional
    public CommonResult<ImUserData> getSingleUserInfo(String userId, String appId) {

        LambdaQueryWrapper<ImUserData> imUserDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
        imUserDataLambdaQueryWrapper.eq(ImUserData::getAppId, appId);
        imUserDataLambdaQueryWrapper.eq(ImUserData::getUserId, userId);
        imUserDataLambdaQueryWrapper.eq(ImUserData::getDelFlag, DelFlagEnum.NORMAL.getCode());

        ImUserData imUserData = baseMapper.selectOne(imUserDataLambdaQueryWrapper);
        if(imUserData == null){
            return CommonResult.failed(UserErrorCode.USER_IS_NOT_EXIST);
        }

        return CommonResult.success(imUserData);
    }

    @Override
    public CommonResult<ImportUserResp> deleteUser(DeleteUserReq req) {
        ImUserData entity = new ImUserData();

        entity.setDelFlag(DelFlagEnum.DELETE.getCode());

        List<String> errorId = new ArrayList();
        List<String> successId = new ArrayList();

        for (String userId : req.getUserIds()) {

            LambdaQueryWrapper<ImUserData> imUserDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
            imUserDataLambdaQueryWrapper.eq(ImUserData::getAppId, req.getAppId());
            imUserDataLambdaQueryWrapper.eq(ImUserData::getUserId, userId);

            imUserDataLambdaQueryWrapper.eq(ImUserData::getDelFlag, DelFlagEnum.NORMAL.getCode());

            int update = 0;

            try {
                update =  baseMapper.update(entity, imUserDataLambdaQueryWrapper);
                if(update > 0){
                    successId.add(userId);
                }else{
                    errorId.add(userId);
                }
            }catch (Exception e){
                errorId.add(userId);
            }
        }

        ImportUserResp resp = new ImportUserResp();
        resp.setSuccessId(successId);
        resp.setErrorId(errorId);
        return CommonResult.success(resp);
    }

    @Override
    public CommonResult modifyUserInfo(ModifyUserInfoReq req) {
        LambdaQueryWrapper<ImUserData> query = new LambdaQueryWrapper<>();
        query.eq(ImUserData::getAppId,req.getAppId());
        query.eq(ImUserData::getUserId,req.getUserId());
        query.eq(ImUserData::getDelFlag,DelFlagEnum.NORMAL.getCode());
        ImUserData user = baseMapper.selectOne(query);
        if(user == null){
            throw new ApplicationException(UserErrorCode.USER_IS_NOT_EXIST);
        }

        ImUserData update = new ImUserData();
        BeanUtils.copyProperties(req,update);

        update.setAppId(null);
        update.setUserId(null);
        int update1 = baseMapper.update(update, query);
        if(update1 == 1){
            // todo: 用户资料消息通知
//            UserModifyPack pack = new UserModifyPack();
//            BeanUtils.copyProperties(req,pack);
//            messageProducer.sendToUser(req.getUserId(),req.getClientType(),req.getImei(),
//                    UserEventCommand.USER_MODIFY,pack,req.getAppId());
//
//            if(appConfig.isModifyUserAfterCallback()){
//                callbackService.callback(req.getAppId(),
//                        Constants.CallbackCommand.ModifyUserAfter,
//                        JSONObject.toJSONString(req));
//            }
            return CommonResult.success();
        }
        throw new ApplicationException(UserErrorCode.MODIFY_USER_ERROR);
    }

    @Override
    public CommonResult login(LoginReq req) {
        return null;
    }

    @Override
    public CommonResult<Map<Object, Object>> getUserSequence(GetUserSequenceReq req) {
        Map<Object, Object> map = stringRedisTemplate.opsForHash()
                .entries(req.getAppId() + ":" + RedisConstants.SeqPrefix + ":" + req.getUserId());
        Long groupSeq = imGroupService.getUserGroupMaxSeq(req.getUserId(),req.getAppId());
        map.put(SeqConstants.GROUP, groupSeq);
        return CommonResult.success(map);
    }

    @Override
    public CommonResult<UserLoginResp> userLogin(UserLoginReq userLoginReq) {
        // 1. 判断有没有这个用户
        LambdaQueryWrapper<ImUserData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ImUserData::getUserId, userLoginReq.getUserId());
        queryWrapper.eq(ImUserData::getAppId, userLoginReq.getAppId());
        queryWrapper.eq(ImUserData::getPassword, userLoginReq.getPassword());

        ImUserData imUserData = baseMapper.selectOne(queryWrapper);

        if (ObjectUtil.isNull(imUserData)) {
            // todo: 枚举
            return CommonResult.failed();
        }

        String token = JwtUtil.createToken(imUserData.getUserId());
        // todo: 枚举，过期时间
        stringRedisTemplate.opsForValue().set("user:im:token:userId:" + imUserData.getUserId(),
                JSONObject.toJSONString(imUserData), 1, TimeUnit.DAYS);

        // 负载均衡获取最佳节点信息
        ImNode bestWorker = imLoadBalance.getBestWorker();

        imUserData.setPassword("");

        UserLoginResp userLoginResp = new UserLoginResp();
        userLoginResp.setImUserData(imUserData);
        userLoginResp.setIp(bestWorker.getHost());
        userLoginResp.setPort(bestWorker.getPort());
        userLoginResp.setUserId(imUserData.getUserId());
        userLoginResp.setToken(token);

        return CommonResult.success(userLoginResp);
    }

    @Override
    public CommonResult checkToken(String token) {
        if (!StringUtils.hasLength(token)) {
            // todo: 枚举
            return CommonResult.failed("用户token不能为空");
        }

        try {
            String s = JwtUtil.checkToken(token);
            if (!StringUtils.hasLength(s)) {
                // todo: 枚举
                return CommonResult.failed("用户token过期或者错误");
            }
            // todo: 枚举
            String userUserJson = stringRedisTemplate.opsForValue().get("user:im:token:userId:" + s);
            ImUserData imUserData = JSONObject.parseObject(userUserJson, ImUserData.class);
            if (ObjectUtil.isNull(imUserData)) {
                // todo: 枚举
                return CommonResult.failed("用户token过期或者错误");
            }
            return CommonResult.success(imUserData);
        }catch (Exception e) {
            e.printStackTrace();
            return CommonResult.failed("用户token过期或者错误");
        }
    }
}




